package com.pay.paytoken.fragment;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.pay.paytoken.R;
import com.pay.paytoken.adapter.TokenCodeAdapter;
import com.pay.paytoken.base.BaseFragment;
import com.zhy.autolayout.AutoLinearLayout;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import apiUtils.apis.GetDataTimeAPI;
import appUtils.LogUtil;
import appUtils.ToastUtil;
import butterknife.Bind;
import butterknife.OnClick;
import constant.AppConstants;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import totpUtils.SPUtils;
import totpUtils.TotpUtil;
import weightUtils.flip.FlipViewController;

import static apiUtils.BaseAPIS.NETWORK_UNKNOWN;
import static constant.AppConstants.TOTP_STEP;
import static totpUtils.config.MTokenConstants.PREFS_SERVICE_TIME_REDUCE;

public class MainTokenFragment extends BaseFragment {

    @Bind(R.id.layout_title_iv_left)
    ImageButton mLayoutTitleIvLeft;
    @Bind(R.id.layout_title_textName)
    TextView mLayoutTitleTextName;
    @Bind(R.id.token_time_tv)
    TextView mTimeTv;
    @Bind(R.id.token_dynamic_pass_tv)
    TextView mDynamicPassTv;
    @Bind(R.id.token_progressBar)
    ProgressBar mProgressBar;
    @Bind(R.id.page1)
    FlipViewController mPage1;
    @Bind(R.id.page2)
    FlipViewController mPage2;
    @Bind(R.id.page3)
    FlipViewController mPage3;
    @Bind(R.id.page4)
    FlipViewController mPage4;
    @Bind(R.id.page5)
    FlipViewController mPage5;
    @Bind(R.id.page6)
    FlipViewController mPage6;
    @Bind(R.id.ll_code)
    AutoLinearLayout mCodeLayout;
    boolean mIsFirst = true;
    int mStep = 3;
    private Disposable mSubscribe, mPageSubscribe;
    private static final int SELECT_NINE = 0x1;
    private static final int PAGE_RESUME = 0x1 << 1;
    private List<FlipViewController> mPages = new ArrayList<>();
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case SELECT_NINE:
                    pagesSelection(9);
                    break;
                case PAGE_RESUME:
                    pagesOnResume();
                    break;
            }
        }
    };
    private List<TokenCodeAdapter> mAdapters = new ArrayList<>();
    private int mCurrentSliding = 0;
    private char[] mCodes;
    //0为未显示，1为显示
    private int mCurrentStatus;

    //将Flip的adapter选中全部更新为第9个
    private void pagesSelection(int i) {
        for (FlipViewController mPage : mPages) {
            mPage.setSelection(i);
        }
    }

    //onResume 更新界面状态为1（显示），将六位令牌显示，初步进入界面需要重新算六位令牌，设置Flip的生命周期关联，根据以保存的六位令牌更新Flip的数字显示
    @Override
    public void onResume() {
        super.onResume();
        mCurrentStatus = 1;
        mCodeLayout.setVisibility(View.VISIBLE);
        mHandler.sendEmptyMessage(PAGE_RESUME);
        setCurrentCodes();
        codeChange();
    }

    private void setCurrentCodes() {
        if (mCodes != null && mCodes.length != 0)
            adaptersSetNumAll(mCodes);
    }

    private void pagesOnResume() {
        for (FlipViewController mPage : mPages) {
            mPage.onResume();
            mPage.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        mCurrentStatus = 0;
        pagesOnPause();
        if (mPageSubscribe != null) {
            mPageSubscribe.dispose();
            mPageSubscribe = null;
            mCurrentSliding = 0;
        }
    }

    private void pagesOnPause() {
        for (FlipViewController mPage : mPages) {
            mPage.onPause();
        }
    }

    @Override
    public void onStop() {
        super.onStop();
        if (AppConstants.isAppFinish) {
            if (mSubscribe != null) {
                mSubscribe.dispose();
                mSubscribe = null;
            }
            if (mPageSubscribe != null) {
                mPageSubscribe.dispose();
                mPageSubscribe = null;
            }
        }
    }

    @Override
    public int setView() {
        return R.layout.fragment_main_bottom_fragment0;
    }

    @Override
    public void initData(Bundle savedInstanceState) {
    }

    @Override
    public void initView() {
        mPages.add(mPage1);
        mPages.add(mPage2);
        mPages.add(mPage3);
        mPages.add(mPage4);
        mPages.add(mPage5);
        mPages.add(mPage6);
        mLayoutTitleIvLeft.setVisibility(View.INVISIBLE);
        mLayoutTitleTextName.setText(getString(R.string.home_bottom_text0));
        mProgressBar.setMax(TOTP_STEP);
        pagesSetAdapter();
        clock();
    }

    private void pagesSetAdapter() {
        for (int i = 0; i < mPages.size(); i++) {
            TokenCodeAdapter adapter = new TokenCodeAdapter();
            mAdapters.add(i, adapter);
            mPages.get(i).setAdapter(adapter);
        }
    }

    private void initDateTime() {
        long timeOff = SPUtils.getLong(PREFS_SERVICE_TIME_REDUCE, 0L);
        long time = timeOff + System.currentTimeMillis();
        @SuppressLint("SimpleDateFormat")
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(time);
        mTimeTv.setText(dateFormat.format(date));
    }

    private void clock() {
        if (mCodes != null && mCodes.length != 0)
            adaptersSetNumAll(mCodes);
        if (mSubscribe == null) {
            mSubscribe = Observable.interval(0, 1, TimeUnit.SECONDS, Schedulers.newThread()).
                    observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<Long>() {
                        @Override
                        public void accept(Long aLong) throws Exception {
                            @SuppressLint("SimpleDateFormat")
                            int currentRate = (int) (Long.parseLong(new SimpleDateFormat("ss").
                                    format(new Date(System.currentTimeMillis() +
                                            SPUtils.getLong(PREFS_SERVICE_TIME_REDUCE, 0L)))) % TOTP_STEP);
                            if (mCurrentStatus == 1) {
                                initDateTime();
                                mProgressBar.setProgress(currentRate == 0 ? TOTP_STEP : currentRate);
                                mDynamicPassTv.setText(getString(R.string.dynamic_pass_to_change) + " "
                                        + (currentRate == 0 ? 100 : (int) ((float) currentRate / TOTP_STEP * 100)) + "%");
                            }
                            if (currentRate == 0) {
                                if (!AppConstants.timeRunning) {
                                    return;
                                }
                                codeChange();
                            }
                        }
                    });
        }
    }

    private void codeChange() {
        String code = TotpUtil.generate();
        char[] chars = code.toCharArray();
        if (mCodes != null && Arrays.equals(mCodes, chars)) {
            return;
        }
        mCodes = chars;
        LogUtil.log("code = " + mCodes[0] + mCodes[1] + mCodes[2] + mCodes[3] + mCodes[4] + mCodes[5]);
        if (!adaptersIsEmpty() && mCurrentStatus == 1) {
            if (mIsFirst) {
                adaptersSetNumAll(mCodes);
                mHandler.sendEmptyMessageDelayed(SELECT_NINE, 2000);
                mIsFirst = false;
                return;
            }
            pagesSimulateSliding();
        }
    }

    private void pagesSimulateSliding() {
        if (mPageSubscribe == null) {
            mPageSubscribe = Observable.interval(0, 300, TimeUnit.MILLISECONDS,
                    Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Consumer<Long>() {
                        @Override
                        public void accept(Long aLong) throws Exception {
                            adaptersSetNum(mCodes[mCurrentSliding]);
                            if (mCurrentStatus == 1) {
                                mPages.get(mCurrentSliding++).slidingPage(mStep);
                            } else {
                                adaptersSetCurrentNum(mCurrentSliding++);
                            }

                            if (mCurrentSliding == 6) {
                                adaptersSetCurrentNumAll();
                                mHandler.sendEmptyMessageDelayed(SELECT_NINE, 2000);
                                mCurrentSliding = 0;
                                if (mPageSubscribe != null) {
                                    mPageSubscribe.dispose();
                                    mPageSubscribe = null;
                                }
                            }
                        }
                    });
        }
    }

    private void adaptersSetCurrentNum(int currentSliding) {
        mAdapters.get(currentSliding).setAllNum();
    }

    private void adaptersSetCurrentNumAll() {
        for (TokenCodeAdapter mAdapter : mAdapters) {
            mAdapter.setAllNum();
        }
    }

    private void adaptersSetNumAll(char[] codes) {
        for (int i = 0; i < mAdapters.size(); i++) {
            mAdapters.get(i).setNum(Character.getNumericValue(codes[i]));
            mAdapters.get(i).setAllNum();
        }
    }

    private void adaptersSetNum(char code) {
        mAdapters.get(mCurrentSliding).setNum(Character.getNumericValue(code));
        mAdapters.get(mCurrentSliding).notifyDataSetChanged();
    }

    private boolean adaptersIsEmpty() {
        if (mAdapters.size() < 6) {
            return true;
        }
        for (TokenCodeAdapter mAdapter : mAdapters) {
            if (mAdapter == null) {
                return true;
            }
        }
        return false;
    }

    @OnClick(R.id.token_time_correct)
    protected void correctTime() {
        showProgress(R.string.loadding);
        new GetDataTimeAPI().getServerTime(new GetDataTimeAPI.Listener() {
            @Override
            public void onSuccess(long deltaTime) {
                dismisProgress();
                ToastUtil.showShort(R.string.time_calibration_success);
                SPUtils.put(PREFS_SERVICE_TIME_REDUCE, deltaTime);
                initDateTime();
                clock();
                codeChange();
            }

            @Override
            public void onFailure(int code) {
                dismisProgress();
                if (code == NETWORK_UNKNOWN) {
                    ToastUtil.showShort(R.string.check_network);
                } else {
                    ToastUtil.showShort(R.string.time_calibration_error);
                }
            }
        });
    }

}
